﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Jbe.TestSuite.Infrastructure.Interface;
using System.Windows.Media;
using System.ComponentModel;
using System.Collections.ObjectModel;
using Microsoft.Practices.Composite.Presentation.Commands;
using System.Windows.Media.Imaging;
using System.Reflection;
using Jbe.Composite.Extensions;
using System.Windows.Input;
using Jbe.TestSuite.Project.Properties;
using System.IO;
using System.Windows;


namespace Jbe.TestSuite.Project.Applications
{
    internal class ProjectViewPresentationModel : PresentationModel<IProjectView>, IHeaderInfoProvider
    {
        public ProjectViewPresentationModel(IProjectView view)
            : base(view)
        {
            ProjectItem rootPerson = new ProjectItem() { Name = "<<Project>>" };

            _rootPerson = new ProjectItemPresentationModel(rootPerson);

            _firstGeneration = new Collection<ProjectItemPresentationModel>(
                new ProjectItemPresentationModel[] 
                { 
                    _rootPerson 
                });

            _searchCommand = new SearchFamilyTreeCommand(this);
        }


        public string HeaderInfo
        {
            get { return Resources.Project; }
        }

        public ImageSource HeaderIcon
        {
            get { return new BitmapImage(ResourceService.GetPackUri("Resources/EventLog.ico")); }
        }

        public string Name
        {
            get;
            private set;
        }

        public void FileDrop(string[] files)
        {
            ProjectItem rootPerson = new ProjectItem() { Name = "<<Project>>" };
            foreach (string file in files)
            {
                if (File.Exists(file))
                {
                    rootPerson.Children.Add(new ProjectItem() { Name = file });
                }
                else if (Directory.Exists(file))
                {
                    AppendChildren(rootPerson, new DirectoryInfo(file));
                }
                else
                {
                    // path doesn't exist.
                }
            }

            _firstGeneration = new Collection<ProjectItemPresentationModel>(
                new ProjectItemPresentationModel[] 
                { 
                    new ProjectItemPresentationModel(rootPerson)
                });
            RaisePropertyChanged("FirstGeneration");
        }

        public void AppendChildren(ProjectItem curItem, DirectoryInfo directory)
        {
            ProjectItem newItem = new ProjectItem() { Name = directory.Name, File = directory.FullName };
            curItem.Children.Add(newItem);
            FileInfo[] files = directory.GetFiles();
            foreach (FileInfo file in files)
            {
                ProjectItem child = new ProjectItem() { Name = file.Name, File = file.FullName };
                newItem.Children.Add(new ProjectItem() { Name = file.Name, File = file.FullName });
            }
            DirectoryInfo[] directoies = directory.GetDirectories();
            foreach (DirectoryInfo subDirectory in directoies)
            {

                AppendChildren(newItem, subDirectory);
            }
        }

        #region IsVisible

        private bool _isVisible = true;
        public bool IsVisible
        {
            get { return _isVisible; }
            set
            {
                if (_isVisible != value)
                {
                    _isVisible = value;
                    RaisePropertyChanged("IsVisible");
                }
            }
        }

        #endregion


        #region Data

        private Collection<ProjectItemPresentationModel> _firstGeneration;
        readonly ProjectItemPresentationModel _rootPerson;
        readonly ICommand _searchCommand;

        IEnumerator<ProjectItemPresentationModel> _matchingPeopleEnumerator;
        string _searchText = String.Empty;

        #endregion // Data

        #region Properties

        #region FirstGeneration

        /// <summary>
        /// Returns a read-only collection containing the first person 
        /// in the family tree, to which the TreeView can bind.
        /// </summary>
        public Collection<ProjectItemPresentationModel> FirstGeneration
        {
            get { return _firstGeneration; }
        }

        #endregion // FirstGeneration

        #region SearchCommand

        /// <summary>
        /// Returns the command used to execute a search in the family tree.
        /// </summary>
        public ICommand SearchCommand
        {
            get { return _searchCommand; }
        }

        private class SearchFamilyTreeCommand : ICommand
        {
            readonly ProjectViewPresentationModel _familyTree;

            public SearchFamilyTreeCommand(ProjectViewPresentationModel familyTree)
            {
                _familyTree = familyTree;
            }

            public bool CanExecute(object parameter)
            {
                return true;
            }

            event EventHandler ICommand.CanExecuteChanged
            {
                // I intentionally left these empty because
                // this command never raises the event, and
                // not using the WeakEvent pattern here can
                // cause memory leaks.  WeakEvent pattern is
                // not simple to implement, so why bother.
                add { }
                remove { }
            }

            public void Execute(object parameter)
            {
                _familyTree.PerformSearch();
            }
        }

        #endregion // SearchCommand

        #region SearchText

        /// <summary>
        /// Gets/sets a fragment of the name to search for.
        /// </summary>
        public string SearchText
        {
            get { return _searchText; }
            set
            {
                if (value == _searchText)
                    return;

                _searchText = value;

                _matchingPeopleEnumerator = null;
            }
        }

        #endregion // SearchText

        #endregion // Properties

        #region Search Logic

        void PerformSearch()
        {
            if (_matchingPeopleEnumerator == null || !_matchingPeopleEnumerator.MoveNext())
                this.VerifyMatchingPeopleEnumerator();

            var person = _matchingPeopleEnumerator.Current;

            if (person == null)
                return;

            // Ensure that this person is in view.
            if (person.Parent != null)
                person.Parent.IsExpanded = true;

            person.IsSelected = true;
        }

        void VerifyMatchingPeopleEnumerator()
        {
            var matches = this.FindMatches(_searchText, null);
            _matchingPeopleEnumerator = matches.GetEnumerator();

            if (!_matchingPeopleEnumerator.MoveNext())
            {
                MessageBox.Show(
                    "No matching names were found.",
                    "Try Again",
                    MessageBoxButton.OK,
                    MessageBoxImage.Information
                    );
            }
        }

        IEnumerable<ProjectItemPresentationModel> FindMatches(string searchText, ProjectItemPresentationModel _person)
        {
            if (_person == null)
            {
                foreach (ProjectItemPresentationModel person in _firstGeneration)
                {
                    if (person.NameContainsText(searchText))
                        yield return person;

                    foreach (ProjectItemPresentationModel child in person.Children)
                        foreach (ProjectItemPresentationModel match in this.FindMatches(searchText, child))
                            yield return match;
                }
            }
            else
            {
                ProjectItemPresentationModel person = _person;
                if (person.NameContainsText(searchText))
                    yield return person;

                foreach (ProjectItemPresentationModel child in person.Children)
                    foreach (ProjectItemPresentationModel match in this.FindMatches(searchText, child))
                        yield return match;
            }
        }

        #endregion // Search Logic
    }
}
